package com.p2p.core;

import android.util.Log;

import com.p2p.define.Constant;
import com.p2p.define.P2PRoomType;
import com.p2p.listener.P2PSocketListener;
import com.p2p.listener.P2PSocketRoomListener;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

public class P2PWebSocketClient extends WebSocketListener {
    private final static String TAG = P2PWebSocketClient.class.getCanonicalName();
    private WebSocket mWebSocket;
    private static P2PSocketListener listener;
    private static Map<String, P2PSocketRoomListener> delegates = new HashMap<>();
    private static P2PWebSocketClient instance = new P2PWebSocketClient();

    static P2PWebSocketClient getInstance(String roomId, P2PSocketRoomListener delegate) {
        delegates.put(roomId, delegate);
        return instance;
    }

    static P2PWebSocketClient getInstance(P2PSocketListener socketListener) {
        listener = socketListener;
        return instance;
    }

    private P2PWebSocketClient() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();
        mWebSocket = okHttpClient.newWebSocket(new Request.Builder().url(Constant.SERVER_SOCKET_URL).build(), this);
    }


    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        Log.e(TAG, "onOpen");
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        onMessage(text);
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {
        super.onMessage(webSocket, bytes);
    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        super.onClosing(webSocket, code, reason);
        Log.e(TAG, "onClosing - " + code + " - " + reason);
    }

    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {
        super.onClosed(webSocket, code, reason);
        Log.e(TAG, "onClosed - " + code + " - " + reason);
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        Log.e(TAG, "onFailure - " + t);
    }

    public void init(final String uid, final String name) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    JSONObject initJson = new JSONObject();
                    initJson.put("action", "init");
                    initJson.put("uid", uid);
                    initJson.put("name", name);
                    sendMessage(initJson.toString());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void join(final String roomId, final P2PRoomType roomType) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    JSONObject joinJson = new JSONObject();
                    joinJson.put("action", "join");
                    joinJson.put("roomId", roomId);
                    joinJson.put("roomType", roomType.ordinal());
                    sendMessage(joinJson.toString());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void leaveRoom(final String roomId, final P2PRoomType roomType) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    JSONObject joinJson = new JSONObject();
                    joinJson.put("action", "leave");
                    joinJson.put("roomId", roomId);
                    joinJson.put("roomType", roomType.ordinal());
                    sendMessage(joinJson.toString());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void onMessage(String message) {
        try {
            JSONObject msgJson = new JSONObject(message);
            String roomId = msgJson.optString("roomId",null);
            if (roomId != null) {
                Log.e(TAG, "onMessage-room-" + roomId + " <-- \n" + message);
                P2PSocketRoomListener delegate = delegates.get(roomId);
                if (delegate != null) delegate.onMessage(msgJson);
            } else {
                Log.e(TAG, "onMessage-global <-- \n" + message);
                String action = msgJson.optString("action");
                switch (action) {
                    case "init":
                        listener.initSuccess();
                        break;
                    case "join":
                        Log.e(TAG, "joinSuccess");
                        listener.joinSuccess();
                    default:
                        break;
                }
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    public void sendMessage(String message) {
        Log.e(TAG, "sendMessage --> \n" + message);
        mWebSocket.send(message);
    }
}
